/* SPDX-License-Identifier: GPL-2.0 */
#ifndef UTILS_CPUMASK_H
#define UTILS_CPUMASK_H

/*
 * Cpumasks provide a bitmap suitable for representing the
 * set of CPU's in a system, one bit position per CPU number.  In general,
 * only CONFIG_NR_CPUS (<= CONFIG_NR_CPUS) bits are valid.
 */
#include <utils/bitmap.h>
#include <utils/const.h>

/* Don't assign or return these: may not be this big! */
typedef struct cpumask { DECLARE_BITMAP(bits, CONFIG_NR_CPUS); } cpumask_t;

/**
 * cpumask_bits - get the bits in a cpumask
 * @maskp: the struct cpumask *
 *
 * You should only assume CONFIG_NR_CPUS bits of this mask are valid.  This is
 * a macro so it's const-correct.
 */
#define cpumask_bits(maskp) ((maskp)->bits)

#define nr_cpumask_bits	    CONFIG_NR_CPUS

/* verify cpu argument to cpumask_* operators */
static inline unsigned int cpumask_check(unsigned int cpu)
{
    return cpu;
}

#if CONFIG_NR_CPUS == 1

/* Uniprocessor.  Assume all masks are "1". */
static inline unsigned int cpumask_first(const struct cpumask *srcp)
{
    return 0;
}

static inline unsigned int cpumask_last(const struct cpumask *srcp)
{
    return 0;
}

/* Valid inputs for n are -1 and 0. */
static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
{
    return n+1;
}

static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
{
    return n+1;
}

static inline unsigned int cpumask_next_and(int n,
                        const struct cpumask *srcp,
                        const struct cpumask *andp)
{
    return n+1;
}

static inline unsigned int cpumask_next_wrap(int n, const struct cpumask *mask,
                         int start, bool wrap)
{
    /* cpu0 unless stop condition, wrap and at cpu0, then nr_cpumask_bits */
    return (wrap && n == 0);
}

/* cpu must be a valid cpu, ie 0, so there's no other choice. */
static inline int cpumask_any_but(const struct cpumask *mask,
                       int cpu)
{
    return 1;
}

#define for_each_cpu(cpu, mask)			\
    for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
#define for_each_cpu_not(cpu, mask)		\
    for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
#define for_each_cpu_wrap(cpu, mask, start)	\
    for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)(start))
#else

/**
 * cpumask_first - get the first cpu in a cpumask
 * @srcp: the cpumask pointer
 *
 * Returns >= CONFIG_NR_CPUS if no cpus set.
 */
static inline unsigned int cpumask_first(const struct cpumask *srcp)
{
    return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
}

/**
 * cpumask_last - get the last CPU in a cpumask
 * @srcp:	- the cpumask pointer
 *
 * Returns	>= nr_cpumask_bits if no CPUs set.
 */
static inline unsigned int cpumask_last(const struct cpumask *srcp)
{
    return find_last_bit(cpumask_bits(srcp), nr_cpumask_bits);
}

unsigned int cpumask_next(int n, const struct cpumask *srcp);

/**
 * cpumask_next_zero - get the next unset cpu in a cpumask
 * @n: the cpu prior to the place to search (ie. return will be > @n)
 * @srcp: the cpumask pointer
 *
 * Returns >= CONFIG_NR_CPUS if no further cpus unset.
 */
static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
{
    /* -1 is a legal arg here. */
    if (n != -1)
        cpumask_check(n);
    return find_next_zero_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
}

int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
int cpumask_any_but(const struct cpumask *mask, int cpu);

/**
 * for_each_cpu - iterate over every cpu in a mask
 * @cpu: the (optionally unsigned) integer iterator
 * @mask: the cpumask pointer
 *
 * After the loop, cpu is >= CONFIG_NR_CPUS.
 */
#define for_each_cpu(cpu, mask)				\
    for ((cpu) = -1;				\
        (cpu) = cpumask_next((cpu), (mask)),	\
        (cpu) < CONFIG_NR_CPUS;)

/**
 * for_each_cpu_not - iterate over every cpu in a complemented mask
 * @cpu: the (optionally unsigned) integer iterator
 * @mask: the cpumask pointer
 *
 * After the loop, cpu is >= CONFIG_NR_CPUS.
 */
#define for_each_cpu_not(cpu, mask)				\
    for ((cpu) = -1;					\
        (cpu) = cpumask_next_zero((cpu), (mask)),	\
        (cpu) < CONFIG_NR_CPUS;)

extern int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap);

/**
 * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location
 * @cpu: the (optionally unsigned) integer iterator
 * @mask: the cpumask poiter
 * @start: the start location
 *
 * The implementation does not assume any bit in @mask is set (including @start).
 *
 * After the loop, cpu is >= CONFIG_NR_CPUS.
 */
#define for_each_cpu_wrap(cpu, mask, start)					\
    for ((cpu) = cpumask_next_wrap((start)-1, (mask), (start), false);	\
         (cpu) < nr_cpumask_bits;						\
         (cpu) = cpumask_next_wrap((cpu), (mask), (start), true))

#endif /* SMP */

#define CPU_BITS_NONE						\
{								\
    [0 ... BITS_TO_LONGS(CONFIG_NR_CPUS)-1] = 0UL			\
}

#define CPU_BITS_CPU0						\
{								\
    [0] =  1UL						\
}

/**
 * cpumask_set_cpu - set a cpu in a cpumask
 * @cpu: cpu number (< CONFIG_NR_CPUS)
 * @dstp: the cpumask pointer
 */
static inline void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
{
    set_bit(cpumask_check(cpu), cpumask_bits(dstp));
}

static inline void __cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
{
    __set_bit(cpumask_check(cpu), cpumask_bits(dstp));
}

/**
 * cpumask_clear_cpu - clear a cpu in a cpumask
 * @cpu: cpu number (< CONFIG_NR_CPUS)
 * @dstp: the cpumask pointer
 */
static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
{
    clear_bit(cpumask_check(cpu), cpumask_bits(dstp));
}

static inline void __cpumask_clear_cpu(int cpu, struct cpumask *dstp)
{
    __clear_bit(cpumask_check(cpu), cpumask_bits(dstp));
}

/**
 * cpumask_test_cpu - test for a cpu in a cpumask
 * @cpu: cpu number (< CONFIG_NR_CPUS)
 * @cpumask: the cpumask pointer
 *
 * Returns 1 if @cpu is set in @cpumask, else returns 0
 */
static inline int cpumask_test_cpu(int cpu, const struct cpumask *cpumask)
{
    return test_bit(cpumask_check(cpu), cpumask_bits((cpumask)));
}

/**
 * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask
 * @cpu: cpu number (< CONFIG_NR_CPUS)
 * @cpumask: the cpumask pointer
 *
 * Returns 1 if @cpu is set in old bitmap of @cpumask, else returns 0
 *
 * test_and_set_bit wrapper for cpumasks.
 */
static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
{
    return test_and_set_bit(cpumask_check(cpu), cpumask_bits(cpumask));
}

/**
 * cpumask_test_and_clear_cpu - atomically test and clear a cpu in a cpumask
 * @cpu: cpu number (< CONFIG_NR_CPUS)
 * @cpumask: the cpumask pointer
 *
 * Returns 1 if @cpu is set in old bitmap of @cpumask, else returns 0
 *
 * test_and_clear_bit wrapper for cpumasks.
 */
static inline int cpumask_test_and_clear_cpu(int cpu, struct cpumask *cpumask)
{
    return test_and_clear_bit(cpumask_check(cpu), cpumask_bits(cpumask));
}

/**
 * cpumask_setall - set all cpus (< CONFIG_NR_CPUS) in a cpumask
 * @dstp: the cpumask pointer
 */
static inline void cpumask_setall(struct cpumask *dstp)
{
    bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits);
}

/**
 * cpumask_clear - clear all cpus (< CONFIG_NR_CPUS) in a cpumask
 * @dstp: the cpumask pointer
 */
static inline void cpumask_clear(struct cpumask *dstp)
{
    bitmap_zero(cpumask_bits(dstp), nr_cpumask_bits);
}

/**
 * cpumask_and - *dstp = *src1p & *src2p
 * @dstp: the cpumask result
 * @src1p: the first input
 * @src2p: the second input
 *
 * If *@dstp is empty, returns 0, else returns 1
 */
static inline int cpumask_and(struct cpumask *dstp,
                   const struct cpumask *src1p,
                   const struct cpumask *src2p)
{
    return bitmap_and(cpumask_bits(dstp), cpumask_bits(src1p),
                       cpumask_bits(src2p), nr_cpumask_bits);
}

/**
 * cpumask_or - *dstp = *src1p | *src2p
 * @dstp: the cpumask result
 * @src1p: the first input
 * @src2p: the second input
 */
static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
                  const struct cpumask *src2p)
{
    bitmap_or(cpumask_bits(dstp), cpumask_bits(src1p),
                      cpumask_bits(src2p), nr_cpumask_bits);
}

/**
 * cpumask_xor - *dstp = *src1p ^ *src2p
 * @dstp: the cpumask result
 * @src1p: the first input
 * @src2p: the second input
 */
static inline void cpumask_xor(struct cpumask *dstp,
                   const struct cpumask *src1p,
                   const struct cpumask *src2p)
{
    bitmap_xor(cpumask_bits(dstp), cpumask_bits(src1p),
                       cpumask_bits(src2p), nr_cpumask_bits);
}

/**
 * cpumask_andnot - *dstp = *src1p & ~*src2p
 * @dstp: the cpumask result
 * @src1p: the first input
 * @src2p: the second input
 *
 * If *@dstp is empty, returns 0, else returns 1
 */
static inline int cpumask_andnot(struct cpumask *dstp,
                  const struct cpumask *src1p,
                  const struct cpumask *src2p)
{
    return bitmap_andnot(cpumask_bits(dstp), cpumask_bits(src1p),
                      cpumask_bits(src2p), nr_cpumask_bits);
}

/**
 * cpumask_complement - *dstp = ~*srcp
 * @dstp: the cpumask result
 * @srcp: the input to invert
 */
static inline void cpumask_complement(struct cpumask *dstp,
                      const struct cpumask *srcp)
{
    bitmap_complement(cpumask_bits(dstp), cpumask_bits(srcp),
                          nr_cpumask_bits);
}

/**
 * cpumask_equal - *src1p == *src2p
 * @src1p: the first input
 * @src2p: the second input
 */
static inline bool cpumask_equal(const struct cpumask *src1p,
                const struct cpumask *src2p)
{
    return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p),
                         nr_cpumask_bits);
}

/**
 * cpumask_intersects - (*src1p & *src2p) != 0
 * @src1p: the first input
 * @src2p: the second input
 */
static inline bool cpumask_intersects(const struct cpumask *src1p,
                     const struct cpumask *src2p)
{
    return bitmap_intersects(cpumask_bits(src1p), cpumask_bits(src2p),
                              nr_cpumask_bits);
}

/**
 * cpumask_empty - *srcp == 0
 * @srcp: the cpumask to that all cpus < CONFIG_NR_CPUS are clear.
 */
static inline bool cpumask_empty(const struct cpumask *srcp)
{
    return bitmap_empty(cpumask_bits(srcp), nr_cpumask_bits);
}

/**
 * cpumask_full - *srcp == 0xFFFFFFFF...
 * @srcp: the cpumask to that all cpus < CONFIG_NR_CPUS are set.
 */
static inline bool cpumask_full(const struct cpumask *srcp)
{
    return bitmap_full(cpumask_bits(srcp), nr_cpumask_bits);
}

/**
 * cpumask_weight - Count of bits in *srcp
 * @srcp: the cpumask to count bits (< CONFIG_NR_CPUS) in.
 */
static inline unsigned int cpumask_weight(const struct cpumask *srcp)
{
    return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits);
}

/**
 * cpumask_copy - *dstp = *srcp
 * @dstp: the result
 * @srcp: the input cpumask
 */
static inline void cpumask_copy(struct cpumask *dstp,
                const struct cpumask *srcp)
{
    bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), nr_cpumask_bits);
}

/**
 * cpumask_any - pick a "random" cpu from *srcp
 * @srcp: the input cpumask
 *
 * Returns >= CONFIG_NR_CPUS if no cpus set.
 */
#define cpumask_any(srcp) cpumask_first(srcp)

/**
 * cpumask_first_and - return the first cpu from *srcp1 & *srcp2
 * @src1p: the first input
 * @src2p: the second input
 *
 * Returns >= nr_cpu_ids if no cpus set in both.  See also cpumask_next_and().
 */
#define cpumask_first_and(src1p, src2p) cpumask_next_and(-1, (src1p), (src2p))

/**
 * cpumask_any_and - pick a "random" cpu from *mask1 & *mask2
 * @mask1: the first input cpumask
 * @mask2: the second input cpumask
 *
 * Returns >= nr_cpu_ids if no cpus set.
 */
#define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2))

/**
 * cpumask_size - size to allocate for a 'struct cpumask' in bytes
 */
static inline unsigned int cpumask_size(void)
{
    return BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long);
}

#if CONFIG_NR_CPUS <= BITS_PER_LONG
#define CPU_BITS_ALL						\
{								\
    [BITS_TO_LONGS(CONFIG_NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(CONFIG_NR_CPUS)	\
}

#else /* CONFIG_NR_CPUS > BITS_PER_LONG */

#define CPU_BITS_ALL						\
{								\
    [0 ... BITS_TO_LONGS(CONFIG_NR_CPUS)-2] = ~0UL,		\
    [BITS_TO_LONGS(CONFIG_NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(CONFIG_NR_CPUS)	\
}
#endif /* CONFIG_NR_CPUS > BITS_PER_LONG */

#if CONFIG_NR_CPUS <= BITS_PER_LONG
#define CPU_MASK_ALL							\
(cpumask_t) { {								\
    [BITS_TO_LONGS(CONFIG_NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(CONFIG_NR_CPUS)	\
} }
#else
#define CPU_MASK_ALL							\
(cpumask_t) { {								\
    [0 ... BITS_TO_LONGS(CONFIG_NR_CPUS)-2] = ~0UL,			\
    [BITS_TO_LONGS(CONFIG_NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(CONFIG_NR_CPUS)	\
} }
#endif /* CONFIG_NR_CPUS > BITS_PER_LONG */

#define CPU_MASK_NONE							\
(cpumask_t) { {								\
    [0 ... BITS_TO_LONGS(CONFIG_NR_CPUS)-1] =  0UL				\
} }

#define CPU_MASK_CPU0							\
(cpumask_t) { {								\
    [0] =  1UL							\
} }

#endif /* !UTILS_CPUMASK_H */
